#include <memory>
#include <string>
#include <sstream>
#include <yaml-cpp/yaml.h>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <functional>

#include "log.h"
#include "util.h"
#include "lexicalcast.h"

namespace sylar {

/**
 * @brief 配置变量的基类
 */
class ConfigVarBase { // 模板类
public:
    using ptr = std::shared_ptr<ConfigVarBase>;
    /**
     * @brief 构造函数
     * @param[in] name 配置参数名称[0-9a-z_.]
     * @param[in] description 配置参数描述
     */
    ConfigVarBase(const std::string& name, const std::string& description = "")
        :m_name(name)
        ,m_description(description) {
        std::transform(m_name.begin(), m_name.end(), m_name.begin(), ::tolower); // 只用小写
    }

    virtual ~ConfigVarBase() {}
    const std::string& getName() const { return m_name;}
    const std::string& getDescription() const { return m_description;}

    // 转成字符串
    virtual std::string toString() = 0;
    // 从字符串初始化值
    virtual bool fromString(const std::string& val) = 0;
    // 返回配置参数值的类型名称
    virtual std::string getTypeName() const = 0;
protected:
    /// 配置参数的名称
    std::string m_name;
    /// 配置参数的描述
    std::string m_description;
};

/**
 * @brief 配置参数模板子类,保存对应类型的参数值
 * @details T 参数的具体类型
 *          FromStr 从std::string转换成T类型的仿函数
 *          ToStr 从T转换成std::string的仿函数
 *          std::string 为YAML格式的字符串
 */
template<class T, class FromStr = LexicalCast<std::string, T>
                ,class ToStr = LexicalCast<T, std::string> >
class ConfigVar : public ConfigVarBase {
public:
    // typedef RWMutex RWMutexType;
    using ptr = std::shared_ptr<ConfigVar>;
    using on_change_cb = std::function<void (const T& old_value, const T& new_value)>;

    /**
     * @brief 通过参数名,参数值,描述构造ConfigVar
     * @param[in] name 参数名称有效字符为[0-9a-z_.]
     * @param[in] default_value 参数的默认值
     * @param[in] description 参数的描述
     */
    ConfigVar(const std::string& name
            ,const T& default_value
            ,const std::string& description = "")
        :ConfigVarBase(name, description)
        ,m_val(default_value) {
    }

    // 参数类型转成 YAML String 类型
    std::string toString() override {
        try {
            // return boost::lexical_cast<std::string>(m_val);
            // RWMutexType::ReadLock lock(m_mutex);
            return ToStr()(m_val);
        } catch (std::exception& e) {
            SYLAR_LOG_ERROR(SYLAR_LOG_ROOT()) << "ConfigVar::toString exception "
                << e.what() << " convert: " << TypeToName<T>() << " to string"
                << " name=" << m_name;
        }
        return "";
    }

    // 从YAML String类型 转成参数的类型 T
    bool fromString(const std::string& val) override {
        try {
            // m_val = boost::lexical_cast<T>(val); // 万能转换器，string转成想要的类型，简单类型的转换
            setValue(FromStr()(val));
        } catch (std::exception& e) {
            SYLAR_LOG_ERROR(SYLAR_LOG_ROOT()) << "ConfigVar::fromString exception "
                << e.what() << " convert: string to " << TypeToName<T>()
                << " name=" << m_name
                << " - " << val;
        }
        return false;
    }

    // 获取当前参数的值 // RWMutexType::ReadLock lock(m_mutex);
    const T getValue() {  return m_val; }

    // 设置当前参数的值  @details 如果参数的值有发生变化,则通知对应的注册回调函数
    void setValue(const T& v) { 
        if(v == m_val) {
                return;
            }
            for(auto& i : m_cbs) {
                i.second(m_val, v);
            }
        m_val = v; 
    }

    // 返回参数值的类型名称(typeinfo)
    std::string getTypeName() const override { return TypeToName<T>();}

    // 添加变化回调函数， 返回该回调函数对应的唯一id，用于删除回调
    uint64_t addListener(on_change_cb cb) {
        static uint64_t s_fun_id = 0;
        // RWMutexType::WriteLock lock(m_mutex);
        ++s_fun_id;
        m_cbs[s_fun_id] = cb;
        return s_fun_id;
    }
    // 删除回调函数，传入参数为回调函数的唯一id
    void delListener(uint64_t key) {
        // RWMutexType::WriteLock lock(m_mutex);
        m_cbs.erase(key);
    }
    // 获取回调函数， key 回调函数的唯一id，如果存在返回对应的回调函数,否则返回nullptr
    on_change_cb getListener(uint64_t key) {
        // RWMutexType::ReadLock lock(m_mutex);
        auto it = m_cbs.find(key);
        return it == m_cbs.end() ? nullptr : it->second;
    }
    // 清理所有的回调函数
    void clearListener() {
        // RWMutexType::WriteLock lock(m_mutex);
        m_cbs.clear();
    }
private:
    // RWMutexType m_mutex;
    T m_val;
    //变更回调函数组, uint64_t key,要求唯一，一般可以用hash
    std::map<uint64_t, on_change_cb> m_cbs;
};

/**
 * @brief ConfigVar的管理类
 * @details 提供便捷的方法创建/访问ConfigVar
 */
class Config {
public:
    using ConfigVarMap = std::unordered_map<std::string, ConfigVarBase::ptr>;

    // name + value + description
    template<class T>
    static typename ConfigVar<T>::ptr Lookup(const std::string& name,
            const T& default_value, const std::string& description = "") {

        auto it = GetDatas().find(name);
        if(it != GetDatas().end()) {
            auto tmp = std::dynamic_pointer_cast<ConfigVar<T> >(it->second); // 智能指针下行转换，ConfigVarBase::ptr =》 ConfigVar<T>，判断是否是正确类型
            if(tmp) {
                SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << "Lookup name=" << name << " exists";
                return tmp;
            } else {
                SYLAR_LOG_ERROR(SYLAR_LOG_ROOT()) << "Lookup name=" << name << " exists but type not "
                        << TypeToName<T>() << " real_type = " << it->second->getTypeName()
                        << " " << it->second->toString();
                return nullptr;
            }
        }

        if(name.find_first_not_of("abcdefghikjlmnopqrstuvwxyz._012345678")
                != std::string::npos) {
            SYLAR_LOG_ERROR(SYLAR_LOG_ROOT()) << "Lookup name invalid " << name;
            throw std::invalid_argument(name);
        }

        typename ConfigVar<T>::ptr v(new ConfigVar<T>(name, default_value, description));
        GetDatas()[name] = v;
        return v;
    }

    template<class T>
    static typename ConfigVar<T>::ptr Lookup(const std::string& name) {
        // RWMutexType::ReadLock lock(GetMutex());
        auto it = GetDatas().find(name);
        if(it == GetDatas().end()) {
            return nullptr;
        }
        return std::dynamic_pointer_cast<ConfigVar<T> >(it->second);
    }

    /**
     * @brief 查找配置参数,返回配置参数的基类
     * @param[in] name 配置参数名称
     */
    static ConfigVarBase::ptr LookupBase(const std::string& name);

    // 使用YAML::Node初始化配置模块
    static void LoadFromYaml(const YAML::Node& root);
private:

    static ConfigVarMap& GetDatas() { // 通过静态成员方法，防止静态成员初始化顺序不一致问题
        static ConfigVarMap s_datas; // 核心数据，map  name-》配置变量的基类（value)
        return s_datas;
    }
};

}